package org.javaboy.sms_login.config;

import jakarta.annotation.PostConstruct;
import org.javaboy.sms_login.service.SendSmsLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitConfig implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback {

    @Autowired
    SendSmsLogService sendSmsLogService;
    // 交换机名称
    public static final String SEND_SMS_EXCHANGE = "send_sms_exchange";
    // 队列名称
    public static final String SEND_SMS_QUEUE = "send_sms_queue";

    @Autowired
    RabbitTemplate rabbitTemplate;

    private static final Logger logger = LoggerFactory.getLogger(RabbitConfig.class);

    @PostConstruct
    public void initRabbitTemplate() {
        // 开启发布确认，无论消息有没有投递到交换机，都会调用回调方法
        rabbitTemplate.setConfirmCallback(this);
        // 开启发布返回，如果消息有没有到达队列，就会调用回调方法
        rabbitTemplate.setReturnsCallback(this);
    }

    @Bean
    Queue myQueue() {
        return new Queue(SEND_SMS_QUEUE, true, false, false);
    }

    @Bean
    DirectExchange myExchange() {
        return new DirectExchange(SEND_SMS_EXCHANGE, true, false);
    }

    @Bean
    Binding myBinding() {
        return BindingBuilder.bind(myQueue()).to(myExchange()).withQueueName();
    }

    /**
     * 确认消息是否到达交换机，到还是没到，都会调用这个方法
     *
     * @param correlationData correlation data for the callback.
     * @param ack             true for ack, false for nack
     * @param cause           An optional cause, for nack, when available, otherwise null.
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {
            logger.info("{} 消息发送成功", correlationData.getId());
            //消息到达 MQ，此时修改数据库中这条消息的状态，将之改为 已发送
            sendSmsLogService.updateStatus(correlationData.getId(), 1);
        }
        //发送失败的话，这里什么都不做
    }

    /**
     * 确认消息是否到达队列，如果没有到达会调用这个方法
     * 如果消息到达队列，则不会调用这个方法
     * @param returned the returned message and metadata.
     */
    @Override
    public void returnedMessage(ReturnedMessage returned) {
        logger.info("消息：{} 未到达队列，原因：{}", returned.getReplyText(), returned.getMessage());
    }
}
